
%{
  open Asp
  open Lexing
  let rec faire_pointeur t n =
  	if (n = 0)
  	then t
  	else (faire_pointeur (Asp.Pointeur(t)) (n-1))
  	
  let rec var_to_type_ident t v =
  	match v with
  	|Identificateur(i) -> (t,i)
  	|Pointeur_var(v2) -> let (t2,i2) = var_to_type_ident t v2 in (Asp.Pointeur(t2),i2)
  	|Tableau(_,_) -> assert false
  	
  let debug a =
  	(*print_string a;
  	print_newline ()*)
  	()
  	 
%}

/* liste des differents token */

%token <int> CST
%token <string> IDENT
%token <string> CHAINE
%token <char> CAR
%token CHAR INT VOID STRUCT UNION
%token IF ELSE FOR WHILE
%token RETURN SIZEOF
%token POINT_VIRGULE VIRGULE
%token PARENTHESE_GAUCHE PARENTHESE_DROITE CROCHET_GAUCHE CROCHET_DROIT
%token ACCOLADE_GAUCHE ACCOLADE_DROITE
%token FLECHE POINT BARBARE HEHE
%token EGAL DIFFERENT INFERIEUR INFERIEUR_EQ SUPERIEUR SUPERIEUR_EQ
%token ASSIGNATION PLUS_PLUS MOINS_MOINS
%token PLUS MOINS ETOILE DIV MODULO POINT_EXCLAMATION REFERENCE
%token EOF

/* définitions des priorités et associativités des tokens */

%right ASSIGNATION
%left BARBARE
%left HEHE
%left EGAL DIFFERENT
%left INFERIEUR INFERIEUR_EQ SUPERIEUR SUPERIEUR_EQ
%left PLUS MOINS
%left ETOILE DIV MODULO
%right POINT_EXCLAMATION PLUS_PLUS MOINS_MOINS REFERENCE uplus uminus uetoile
%left PARENTHESE_GAUCHE PARENTHESE_DROITE CROCHET_GAUCHE CROCHET_DROIT ACCOLADE_GAUCHE ACCOLADE_DROITE FLECHE POINT 
%right ELSE
 
/* point d entrée de la grammaire */
%start fichier

/* type des valeurs retournées par l analyseur syntaxique */
%type <Asp.instr_declaration_list> fichier

%%
fichier:
|decl_etoile EOF {$1}
;

decl_etoile:
|decl decl_etoile {$1@$2}
| {[]}
;

decl:
|decl_typ {debug "decl_typ"; [$1]}
|decl_vars {debug "decl_vars"; List.fold_left (fun b e -> Asp.Declaration_var_g(fst e, snd e)::b) [] $1}
|decl_fct {debug "decl_fct"; [$1]}
;

decl_vars:
|typ vars POINT_VIRGULE {List.fold_left (fun b e -> (e,$1)::b) [] $2}
;

decl_vars_etoile:
|decl_vars decl_vars_etoile {$1@$2}
| {[]}
;

decl_typ:
|STRUCT IDENT ACCOLADE_GAUCHE decl_vars_etoile ACCOLADE_DROITE POINT_VIRGULE {Struct($2,$4)}
|UNION IDENT ACCOLADE_GAUCHE decl_vars_etoile ACCOLADE_DROITE POINT_VIRGULE {Union($2,$4)}
;

etoile_etoile:
|ETOILE etoile_etoile %prec uetoile {debug "**";$2 + 1}
| {debug "**";0}
;

arguments_interrogation:
|arguments {debug "arguments";$1}
| {debug "arguments";[]}
;

decl_fct:
|typ var PARENTHESE_GAUCHE arguments_interrogation PARENTHESE_DROITE bloc {
	let (t,i) = var_to_type_ident $1 $2 in
	Asp.Declaration_fun(i,t,$4,$6)}
;

typ:
|VOID {debug "typ:void";Asp.Void}
|INT {debug "typ:int";Asp.Entier}
|CHAR {debug "typ:char";Asp.Caractere}
|STRUCT IDENT {debug "typ:struct";Asp.Type_struct($2)}
|UNION IDENT {debug "typ:union";Asp.Type_union($2)}
;

arguments:
|typ var {[Asp.Argument($2,$1)]}
|typ var VIRGULE arguments {Asp.Argument($2,$1)::$4}
;

var:
|IDENT {Asp.Identificateur($1)}
|ETOILE var %prec uetoile {Asp.Pointeur_var($2)}
|var CROCHET_GAUCHE CST CROCHET_DROIT {Asp.Tableau($1,$3)}
;

vars:
|var {[$1]}
|var VIRGULE vars {$1::$3}
;

expr:
|CST {Asp.Cst($1)}
|CAR {Asp.Car($1)}
|CHAINE {Asp.Chaine($1)}
|IDENT {Asp.Ident($1)}
|ETOILE expr %prec uetoile {Asp.Acces_pointeur($2)}
|expr CROCHET_GAUCHE expr CROCHET_DROIT {Asp.Acces_tableau($1,$3)}
|expr POINT IDENT {Asp.Contenu_variable($1,$3)}
|expr FLECHE IDENT {Asp.Contenu_pointeur($1,$3)}
|expr ASSIGNATION expr {Asp.Assignation($1,$3)}
|IDENT PARENTHESE_GAUCHE l_expr PARENTHESE_DROITE {Asp.Appel_fun($1,$3)}
|PLUS_PLUS expr {Asp.Plus_Plus_Expr($2)}
|MOINS_MOINS expr {Asp.Moins_Moins_Expr($2)}
|expr PLUS_PLUS {Asp.Expr_Plus_Plus($1)}
|expr MOINS_MOINS {Asp.Expr_Moins_Moins($1)}
|REFERENCE expr {Asp.Reference($2)}
|POINT_EXCLAMATION expr {Asp.Non($2)}
|MOINS expr %prec uminus {Asp.Binop(Asp.Soustraction,Asp.Cst(0),$2)}
|PLUS expr %prec uplus {Asp.Binop(Asp.Somme,Asp.Cst(0),$2)}
|operation {$1}
|SIZEOF PARENTHESE_GAUCHE cplx_type PARENTHESE_DROITE {Asp.Sizeof($3)}
|PARENTHESE_GAUCHE expr PARENTHESE_DROITE {$2}
;

operation:
|expr EGAL expr {Asp.Binop(Asp.Egal,$1,$3)}
|expr DIFFERENT expr {Asp.Binop(Asp.Different,$1,$3)}
|expr INFERIEUR expr {Asp.Binop(Asp.Inf,$1,$3)}
|expr INFERIEUR_EQ expr {Asp.Binop(Asp.Inf_eq,$1,$3)}
|expr SUPERIEUR expr {Asp.Binop(Asp.Sup,$1,$3)}
|expr SUPERIEUR_EQ expr {Asp.Binop(Asp.Sup_eq,$1,$3)}
|expr PLUS expr {Asp.Binop(Asp.Somme,$1,$3)}
|expr MOINS expr {Asp.Binop(Asp.Soustraction,$1,$3)}
|expr ETOILE expr {Asp.Binop(Asp.Multiplication,$1,$3)}
|expr DIV expr {Asp.Binop(Asp.Division,$1,$3)}
|expr MODULO expr {Asp.Binop(Asp.Modulo,$1,$3)}
|expr HEHE expr {Asp.Binop(Asp.Et,$1,$3)}
|expr BARBARE expr {Asp.Binop(Asp.Ou,$1,$3)}
;

crochet_etoile:
|CROCHET_GAUCHE CST CROCHET_DROIT crochet_etoile {$2::$4}
| {[]}
;

cplx_type:
|typ etoile_etoile crochet_etoile {Asp.Type_complexe((faire_pointeur $1 $2),$3)}
;

l_expr:
|expr {[$1]}
|expr VIRGULE l_expr {$1::$3}
;

l_expr_interrogation:
|l_expr {$1}
| {[]}
;

expr_interrogation:
|expr {$1}
| {Asp.NOP}
;

instruction:
|expr POINT_VIRGULE {Expression($1)}
|IF PARENTHESE_GAUCHE expr PARENTHESE_DROITE instruction ELSE instruction
	{Asp.If($3,$5,$7)}
|IF PARENTHESE_GAUCHE expr PARENTHESE_DROITE instruction
	{Asp.If($3,$5,Bloc([],[]))}
|WHILE PARENTHESE_GAUCHE expr PARENTHESE_DROITE instruction
	{Asp.While($3,$5)}
|FOR PARENTHESE_GAUCHE l_expr_interrogation POINT_VIRGULE expr_interrogation POINT_VIRGULE l_expr_interrogation PARENTHESE_DROITE instruction
	{Asp.For($3,$5,$7,$9)}
|bloc {$1}
|RETURN expr_interrogation POINT_VIRGULE {Asp.Retour($2)}
;

instruction_etoile:
|instruction instruction_etoile {$1::$2}
| {[]}
;

bloc:
|ACCOLADE_GAUCHE decl_vars_etoile instruction_etoile ACCOLADE_DROITE {Asp.Bloc((List.fold_left (fun b e -> Asp.Declaration_var_g(fst e, snd e)::b) [] $2),$3)}
;

